/*
 * Copyright (c) 2024 Shenzhen Kaihong Digital Industry Development Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "sle_connect_hal.h"
#include "sle_device_config.h"
#include "sle_hilog.h"
#include "sle_loader_hal.h"
#include <stdlib.h>
#include <stdio.h>

static SleConnectHdiOpts *g_sleConnectHalOpts = NULL;
static SleConnectHdiCallbacks *g_sleConnectHdiCbks = NULL;
static SleConnectHalCallbacks *g_sleConnectHalCbks = NULL;

static void OnSleHdiConnectStateChangedCallback(uint16_t connectId, const SleDeviceAddress *addr,
    SleAcbState connState, SlePairState pairState, SleDisConnectReason discReason)
{
    SLE_LOGI("OnSleHdiConnectStateChangedCallback connectId = %{public}d, addr =" MACSTRPRI ", connState = %{public}d, pairState = %{public}d, discReason = (%{public}d)"
        , connectId, MAC2STRPRI(addr->addr), connState, pairState, discReason);
    if (g_sleConnectHalCbks != NULL && g_sleConnectHalCbks->OnConnectHalConnectStateChangeCb != NULL) {
        g_sleConnectHalCbks->OnConnectHalConnectStateChangeCb(connectId, addr, connState, pairState, discReason);
    }
}

static void OnSleHdiConnectParamUpdatedCallback(uint16_t connectId, SleHdiErrorCode ret,
    const SleConnectionParamUpdateEvt *param)
{
    SLE_LOGI("OnSleHdiConnectParamUpdatedCallback connectId = %{public}d, ret = 0x%{public}08X", connectId, ret);
    SLE_LOGD("\t  interval(%{public}d) latency(%{public}d) timeout(%{public}d)", param->interval, param->latency, param->supervisionTimeout);
    SleHalErrorCode halErrcode = SleHalGetErrorCode(ret);
    if(g_sleConnectHalCbks != NULL && g_sleConnectHalCbks->OnConnectHalConnectParamUpdateCompleteCb != NULL) {
        g_sleConnectHalCbks->OnConnectHalConnectParamUpdateCompleteCb(connectId, halErrcode, param);
    }
}

static void OnSleHdiRequestConnectParamUpdateCallback(uint16_t connectId, SleHdiErrorCode ret,
    const SleConnectParam *param)
{
    SLE_LOGI("OnSleHdiRequestConnectParamUpdateCallback connectId = %{public}d, ret = 0x%{public}08X"
        ,connectId, ret);
    SleHalErrorCode halErrcode = SleHalGetErrorCode(ret);
    if(g_sleConnectHalCbks != NULL && g_sleConnectHalCbks->OnConnectHalConnectParamUpdateReqCb != NULL) {
        g_sleConnectHalCbks->OnConnectHalConnectParamUpdateReqCb(connectId, halErrcode, param);
    }
}

static void OnSleHdiAuthCompletedCallback(uint16_t connectId, const SleDeviceAddress *addr, SleHdiErrorCode ret,
    const SleAuthInfo* evt)
{
    SLE_LOGD("OnSleHdiAuthCompletedCallback connectId = %{public}d, addr = "MACSTRPRI", errCode(0x%{public}08X)"
        , connectId, MAC2STRPRI(addr->addr), ret);
    SleHalErrorCode halErrcode = SleHalGetErrorCode(ret);
    if(g_sleConnectHalCbks != NULL && g_sleConnectHalCbks->OnConnectHalAuthCompleteCb != NULL) {
        g_sleConnectHalCbks->OnConnectHalAuthCompleteCb(connectId, addr, halErrcode, evt);
    }
}

static void OnSleHdiPairCompletedCallback(uint16_t connectId, const SleDeviceAddress *addr, SleHdiErrorCode ret)
{
    SLE_LOGI("OnSleHdiPairCompletedCallback connectId = %{public}d, addr = "MACSTRPRI", ret = 0x%{public}08X"
        , connectId, MAC2STRPRI(addr->addr), ret);
    SleHalErrorCode halErrcode = SleHalGetErrorCode(ret);
    if(g_sleConnectHalCbks != NULL && g_sleConnectHalCbks->OnConnectHalPairCompleteCb != NULL) {
        g_sleConnectHalCbks->OnConnectHalPairCompleteCb(connectId, addr, halErrcode);
    }
}

static void OnSleHdiReadRssiCallback(uint16_t connectId, int8_t rssi, SleHdiErrorCode ret)
{
    SLE_LOGD("OnSleHdiReadRssiCallback connectId = %{public}d, rssi = %{public}d, ret = 0x%{public}08X"
        , connectId, rssi, ret);
    SleHalErrorCode halErrcode = SleHalGetErrorCode(ret);
    if(g_sleConnectHalCbks != NULL && g_sleConnectHalCbks->OnConnectHalReadRssiCompleteCb != NULL) {
        g_sleConnectHalCbks->OnConnectHalReadRssiCompleteCb(connectId, rssi, halErrcode);
    }
}

static void OnSleHdiSetPhyParamCallback(uint16_t connectId, SleHalErrorCode ret, const SleConnectionPhyParam *param)
{
    SLE_LOGD("OnSleHdiSetPhyParamCallback connectId = %{public}d, ret = 0x%{public}08X", connectId, ret);
    SleHalErrorCode halErrcode = SleHalGetErrorCode(ret);
    if(g_sleConnectHalCbks != NULL && g_sleConnectHalCbks->OnConnectHalSetPhyParamCompleteCb != NULL) {
        g_sleConnectHalCbks->OnConnectHalSetPhyParamCompleteCb(connectId, halErrcode, param);
    }
}

SleHalErrorCode InitSleConnectHal(void)
{
    SLE_LOGI("InitSleConnectHal");
    SLE_ASSERT_AND_RETURN_RET_LOG(g_sleConnectHalOpts == NULL, SLE_HAL_SUCCESS, "sleConnectHal has been Inited");
    SleHalErrorCode ret = SLE_HAL_ERR_UNKNOWN;
    g_sleConnectHalOpts = (SleConnectHdiOpts*)malloc(sizeof(SleConnectHdiOpts));
    ret = GetSleConnectHalOpts(g_sleConnectHalOpts);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_HAL_SUCCESS, ret, "GetSleConnectHalOpts fail(%{public}d)", ret);
    SLE_ASSERT_AND_RETURN_RET(g_sleConnectHalOpts != NULL, SLE_HAL_ERR_DRIVER_OR_SYSTEM);
    if(g_sleConnectHdiCbks == NULL) {
        g_sleConnectHdiCbks = (SleConnectHdiCallbacks*)malloc(sizeof(SleConnectHdiCallbacks));
        g_sleConnectHdiCbks->OnConnectStateChangedCb = OnSleHdiConnectStateChangedCallback;
        g_sleConnectHdiCbks->OnConnectParamUpdateReqCb = OnSleHdiRequestConnectParamUpdateCallback;
        g_sleConnectHdiCbks->OnConnectParamUpdateCb = OnSleHdiConnectParamUpdatedCallback;
        g_sleConnectHdiCbks->OnAuthCompleteCb = OnSleHdiAuthCompletedCallback;
        g_sleConnectHdiCbks->OnPairCompleteCb = OnSleHdiPairCompletedCallback;
        g_sleConnectHdiCbks->OnReadRssiCb = OnSleHdiReadRssiCallback;
        g_sleConnectHdiCbks->OnSetPhyParamCb = OnSleHdiSetPhyParamCallback;
        SLE_ASSERT_AND_RETURN_RET_LOG(g_sleConnectHdiCbks != NULL, SLE_HAL_ERR_DRIVER_OR_SYSTEM, "SleHal or SleDriver has not been inited");
    }
    SleHdiErrorCode result = g_sleConnectHalOpts->registerConnectCbks(g_sleConnectHdiCbks);
    ret = SleHalGetErrorCode(result);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_HAL_SUCCESS, ret, "registerConnectCbks fail(0x%{public}08X)", result);
    g_sleConnectHalCbks = (SleConnectHalCallbacks*)malloc(sizeof(SleConnectHalCallbacks));
    return ret;
}

SleHalErrorCode DeinitSleConnectHal(void)
{
    SLE_LOGI("DeinitSleConnectHal");
    SLE_ASSERT_AND_RETURN_RET_LOG(g_sleConnectHalOpts != NULL, SLE_HAL_SUCCESS, "sleConnectHal has not been Inited");
    free(g_sleConnectHalOpts);
    g_sleConnectHalOpts = NULL;
    free(g_sleConnectHdiCbks);
    g_sleConnectHdiCbks = NULL;
    free(g_sleConnectHalCbks);
    g_sleConnectHalCbks = NULL;
    return SLE_HAL_SUCCESS;
}

SleHalErrorCode SleConnectHalConnect(const SleDeviceAddress *address)
{
    SLE_LOGI("SleConnectHalConnect addr("MACSTRPRI")", MAC2STRPRI(address->addr));
    SLE_ASSERT_AND_RETURN_RET(g_sleConnectHalOpts != NULL, SLE_HAL_ERR_NOT_READY);
    SLE_ASSERT_AND_RETURN_RET(address != NULL, SLE_HAL_ERR_INVALID_PARAM);
    SleHdiErrorCode result = g_sleConnectHalOpts->connectRemote(address);
    SleHalErrorCode ret = SleHalGetErrorCode(result);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_HAL_SUCCESS, ret, "connectRemote fail(0x%{public}08X)", result);
    return ret;
}

SleHalErrorCode SleConnectHalDisconnect(const SleDeviceAddress *address)
{
    SLE_LOGI("SleConnectHalDisconnect addr("MACSTRPRI")", MAC2STRPRI(address->addr));
    SLE_ASSERT_AND_RETURN_RET(g_sleConnectHalOpts != NULL, SLE_HAL_ERR_NOT_READY);
    SLE_ASSERT_AND_RETURN_RET(address != NULL, SLE_HAL_ERR_INVALID_PARAM);
    SleHdiErrorCode result = g_sleConnectHalOpts->disconnectRemote(address);
    SleHalErrorCode ret = SleHalGetErrorCode(result);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_HAL_SUCCESS, ret, "disconnectRemote fail(0x%{public}08X)", result);
    return ret;
}

SleHalErrorCode SleConnectHalUpdateConnParam(const SleConnectionParamUpdate *param)
{
    SLE_LOGI("SleConnectHalUpdateConnParam connectId(%{public}d)", param->connectId);
    SLE_LOGD("\t  interval[(%{public}d:%{public}d] latency(%{public}d) timeout(%{public}d)", param->intervalMin, param->intervalMax, param->maxLatency, param->supervisionTimeout);
    SLE_ASSERT_AND_RETURN_RET(g_sleConnectHalOpts != NULL, SLE_HAL_ERR_NOT_READY);
    SLE_ASSERT_AND_RETURN_RET(param != NULL, SLE_HAL_ERR_INVALID_PARAM);
    SleHdiErrorCode result = g_sleConnectHalOpts->updateConnectParam(param);
    SleHalErrorCode ret = SleHalGetErrorCode(result);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_HAL_SUCCESS, ret, "updateConnectParam fail(0x%{public}08X)", result);
    return ret;
}

SleHalErrorCode SleConnectHalSetDataLength(uint16_t connectId, uint16_t dataMaxLen)
{
    SLE_LOGD("SleConnectHalSetDataLength connectId(%{public}d) datalen(%{public}d)", connectId, dataMaxLen);
    SLE_ASSERT_AND_RETURN_RET(g_sleConnectHalOpts != NULL, SLE_HAL_ERR_NOT_READY);
    SleHdiErrorCode result = g_sleConnectHalOpts->setDataLen(connectId, dataMaxLen);
    SleHalErrorCode ret = SleHalGetErrorCode(result);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_HAL_SUCCESS, ret, "setDataLength fail(0x%{public}08X)", result);
    return ret;
}

SleHalErrorCode SleConnectHalSetPhyParam(uint16_t connectId, const SleConnectionPhyParam *phyParam)
{
    SLE_LOGD("SleConnectHalSetPhyMcs connectId(%{public}d)", connectId);
    SLE_ASSERT_AND_RETURN_RET(g_sleConnectHalOpts != NULL, SLE_HAL_ERR_NOT_READY);
    SleHdiErrorCode result = g_sleConnectHalOpts->setPhyParam(connectId, phyParam);
    SleHalErrorCode ret = SleHalGetErrorCode(result);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_HAL_SUCCESS, ret, "setPhyParam fail(0x%{public}08X)", result);
    return ret;
}

SleHalErrorCode SleConnectHalSetMcsValue(uint16_t connectId, uint8_t mcs)
{
    SLE_LOGD("SleConnectHalSetMcsValue connectId(%{public}d) mcs(%hu)", connectId, mcs);
    SLE_ASSERT_AND_RETURN_RET(g_sleConnectHalOpts != NULL, SLE_HAL_ERR_NOT_READY);
    SleHdiErrorCode result = g_sleConnectHalOpts->setMcsValue(connectId, mcs);
    SleHalErrorCode ret = SleHalGetErrorCode(result);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_HAL_SUCCESS, ret, "setMcsValue fail(0x%{public}08X)", result);
    return ret;
}

SleHalErrorCode SleConnectHalSendPairReq(const SleDeviceAddress *address)
{
    SLE_LOGI("SleConnectHalSendPairReq addr("MACSTRPRI")", MAC2STRPRI(address->addr));
    SLE_ASSERT_AND_RETURN_RET(g_sleConnectHalOpts != NULL, SLE_HAL_ERR_NOT_READY);
    SLE_ASSERT_AND_RETURN_RET(address != NULL, SLE_HAL_ERR_INVALID_PARAM);
    SleHdiErrorCode result = g_sleConnectHalOpts->sendPairReq(address);
    SleHalErrorCode ret = SleHalGetErrorCode(result);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_HAL_SUCCESS, ret, "sendPairReq fail(0x%{public}08X)", result);
    return ret;
}

SleHalErrorCode SleConnectHalRemovePair(const SleDeviceAddress *address)
{
    SLE_LOGI("SleConnectHalRemovePair addr("MACSTRPRI")", MAC2STRPRI(address->addr));
    SLE_ASSERT_AND_RETURN_RET(g_sleConnectHalOpts != NULL, SLE_HAL_ERR_NOT_READY);
    SLE_ASSERT_AND_RETURN_RET(address != NULL, SLE_HAL_ERR_INVALID_PARAM);
    SleHdiErrorCode result = g_sleConnectHalOpts->removePairDevice(address);
    SleHalErrorCode ret = SleHalGetErrorCode(result);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_HAL_SUCCESS, ret, "removePairDevice fail(0x%{public}08X)", result);
    return ret;
}

SleHalErrorCode SleConnectHalRemoveAllPairs(void)
{
    SLE_LOGD("SleConnectHalRemoveAllPairs");
    SLE_ASSERT_AND_RETURN_RET(g_sleConnectHalOpts != NULL, SLE_HAL_ERR_NOT_READY);
    SleHdiErrorCode result = g_sleConnectHalOpts->removeAllPairs();
    SleHalErrorCode ret = SleHalGetErrorCode(result);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_HAL_SUCCESS, ret, "removeAllPairs fail(0x%{public}08X)", result);
    return ret;
}

SleHalErrorCode SleConnectHalGetPairedDevicesNum(uint16_t *number)
{
    SLE_LOGD("SleConnectHalGetPairedDevicesNum");
    SLE_ASSERT_AND_RETURN_RET(g_sleConnectHalOpts != NULL, SLE_HAL_ERR_NOT_READY);
    SLE_ASSERT_AND_RETURN_RET(number != NULL, SLE_HAL_ERR_INVALID_PARAM);
    SleHdiErrorCode result = g_sleConnectHalOpts->getPairedDevicesNum(number);
    SleHalErrorCode ret = SleHalGetErrorCode(result);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_HAL_SUCCESS, ret, "getPairedDevicesNum fail(0x%{public}08X)", result);
    return ret;
}

SleHalErrorCode SleConnectHalGetPairedDevices(SleDeviceAddress *pairedDevices, uint16_t *number)
{
    SLE_LOGD("HalGetPairedDevices");
    SLE_ASSERT_AND_RETURN_RET(g_sleConnectHalOpts != NULL, SLE_HAL_ERR_NOT_READY);
    SLE_ASSERT_AND_RETURN_RET(pairedDevices != NULL, SLE_HAL_ERR_INVALID_PARAM);
    SLE_ASSERT_AND_RETURN_RET(number != NULL, SLE_HAL_ERR_INVALID_PARAM);
    SleHdiErrorCode result = g_sleConnectHalOpts->getPairedDevices(pairedDevices, number);
    SleHalErrorCode ret = SleHalGetErrorCode(result);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_HAL_SUCCESS, ret, "getPairedDevices fail(0x%{public}08X)", result);
    return ret;
}

SleHalErrorCode SleConnectHalGetPairState(const SleDeviceAddress *connDevAddress, SlePairState *state)
{
    SLE_LOGD("SleConnectHalGetPairState");
    SLE_ASSERT_AND_RETURN_RET(g_sleConnectHalOpts != NULL, SLE_HAL_ERR_NOT_READY);
    SLE_ASSERT_AND_RETURN_RET(connDevAddress != NULL, SLE_HAL_ERR_INVALID_PARAM);
    SLE_ASSERT_AND_RETURN_RET(state != NULL, SLE_HAL_ERR_INVALID_PARAM);
    SleHdiErrorCode result = g_sleConnectHalOpts->getPairState(connDevAddress, state);
    SleHalErrorCode ret = SleHalGetErrorCode(result);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_HAL_SUCCESS, ret, "getPairState fail(0x%{public}08X)", result);
    return ret;
}

SleHalErrorCode SleConnectHalRegisterCallbacks(const SleConnectHalCallbacks *callback)
{
    SLE_LOGI("SleConnectHalRegisterCallbacks");
    SLE_ASSERT_AND_RETURN_RET(g_sleConnectHalOpts != NULL, SLE_HAL_ERR_NOT_READY);
    SLE_ASSERT_AND_RETURN_RET(callback != NULL, SLE_HAL_ERR_INVALID_PARAM);
    memcpy(g_sleConnectHalCbks, callback, sizeof(SleConnectHalCallbacks));
    return SLE_HAL_SUCCESS;
}

SleHalErrorCode SleConnectHalReadRemoteRssi(uint16_t connectId)
{
    SLE_LOGD("SleConnectHalReadRemoteRssi");
    SLE_ASSERT_AND_RETURN_RET(g_sleConnectHalOpts != NULL, SLE_HAL_ERR_NOT_READY);
    SleHdiErrorCode result = g_sleConnectHalOpts->readRemoteRssi(connectId);
    SleHalErrorCode ret = SleHalGetErrorCode(result);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_HAL_SUCCESS, ret, "readRemoteRssi fail(0x%{public}08X)", result);
    return ret;
}

SleHalErrorCode SleConnectHalSetDefaultConnParam(const SleDefaultConnectionParam *defaultConnParam)
{
    SLE_LOGD("SleConnectHalSetDefaultConnParam");
    SLE_ASSERT_AND_RETURN_RET(g_sleConnectHalOpts != NULL, SLE_HAL_ERR_NOT_READY);
    SLE_ASSERT_AND_RETURN_RET(defaultConnParam != NULL, SLE_HAL_ERR_INVALID_PARAM);
    SleHdiErrorCode result = g_sleConnectHalOpts->setDefaultConnParam(defaultConnParam);
    SleHalErrorCode ret = SleHalGetErrorCode(result);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_HAL_SUCCESS, ret, "setDefaultConnParam fail(0x%{public}08X)", result);
    return ret;
}

